/**
 * A filter that filter the source URLs by the definition in a regex-file. 
 * regex-file Demo:
 *      #this is comment.
 *      #the following line show an acceptable filter.
 *      +^http:.*
 *      #the following line show an unacceptable filter.
 *      -^.*
 *      #each statement(comment included) occupies a single line.
 */
package com.javacrawler.tool;

import java.util.regex.*;
import java.util.*;
import java.io.*;
/**
 * @author ailen-cootek
 *
 */
public class Filter {
    private static class FiltItem {
        public boolean accept;
        public Pattern pattern;
        
        public FiltItem(boolean accept, String regex)
        {
            this.accept = accept;
            this.pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        }
    }
    
    private LinkedList<FiltItem> items;
    /**
     * @param args
     * @throws RegexFileError 
     */
    public static void main(String[] args) throws RegexFileError {
        Filter filter = Filter.parse("regex-urlfilter.txt");
        System.out.println(filter.accept("http://test.com"));
        System.out.println(filter.accept("http://test.com/page/1"));
    }
    
    private Filter()
    {
        this.items = new LinkedList<FiltItem>();
    }
    
    /**
     * Generate a filter from a input file.
     * @param fName -- name of the file, path included.
     * @return  the filter.
     * @throws RegexFileError   something wrong with the regex-file.
     */
    public static Filter parse(String fName) throws RegexFileError
    {
        File file = new File(fName);
        Filter filter = new Filter();
        if (!file.exists() || file.isDirectory())
            throw new RegexFileError("Regex file " + fName + " missing.");
        try {
            int lineNum = 0;
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String line = null;
            while ((line = reader.readLine()) != null)
            {
                lineNum++;
                line = line.trim();
                if (line.equals("") || line.startsWith("#"))
                    continue;
                if (line.startsWith("+"))
                {
                    filter.items.add(new FiltItem(true, line.substring(1)));
                }
                else if (line.startsWith("-"))
                {
                    filter.items.add(new FiltItem(false, line.substring(1)));
                }
                else
                {
                    throw new RegexFileError("Regex error at line " + lineNum + ".");
                }
            }
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RegexFileError("Error when reading from " + fName);
        }
        return filter;
    }
    
    /**
     * Check whether the src is acceptable.
     * @param src   -- the src to check.
     * @return  true if, and only if, the src is accepted; false otherwise.
     */
    public boolean accept(String src)
    {
        for (int i = 0; i < this.items.size(); i ++)
        {
            FiltItem each = this.items.get(i);
            Matcher matcher = each.pattern.matcher(src);
            if (matcher.find())
            {
                return each.accept;
            }
        }
        return false;
    }
}
